package seismosurfer.update;

import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import seismosurfer.data.MagData;
import seismosurfer.data.QuakeAggregate;
import seismosurfer.data.QuakeData;
import seismosurfer.database.DB;
import seismosurfer.database.QuakeDAO;
import seismosurfer.util.Assert;
import seismosurfer.util.TimeUtil;
import seismosurfer.util.UserException;

import com.bbn.openmap.util.Debug;

/**
 * An extension to Updater for the US (NEIC)
 * catalogs.
 *
 */
public class NEICUpdater extends Updater {

    public NEICUpdater(int catalogID) {
        super(catalogID);
    }

    protected void insert(QuakeData qd) {
        try {
            // Begin transaction
            DB.begin();

            QuakeDAO dao = new QuakeDAO();

            // Insert the new quake data into the QUAKE table
            dao.insertQuake(qd);

            Collection mags = ((QuakeAggregate) qd).getMagnitudes();

            for (Iterator iter = mags.iterator(); iter.hasNext();) {
                MagData item = (MagData) iter.next();
                dao.insertMagnitude(item);
            }

            // End transaction
            DB.commit();
        } catch (SQLException e) {
            DB.handleTransactionError(e);
        }
    }

    private String stripRedundant(String line, String catalogName) {
        int start = line.indexOf(catalogName);
        return line.substring(start - 1, start + 89);
    }

    protected void parse() {

        String line;
        int count = 0;
        int index = 0;
        long time;

        Iterator it = data.iterator();

        // add data lines to list
        while (it.hasNext()) {
            line = (String) it.next();
            count++;

            if (Debug.debugging("update")) {
                Debug.output("Line " + count + ": " + line);
            }

            // skip empty lines
            if (empty(line)) {
                continue;
            }

            index = line.indexOf(this.catalog.getCatalogName());
            if (index == -1) {
                // skip lines that don`t have catalog`s name (e.g. PDE)
                continue;
            }
            // else if (!line.trim().startsWith(this.catalog.getCatalogName()))
            // {
            // //skip lines that don`t start with catalog`s name
            // Debug.output("Line :" + line.substring(index, index + 6));
            // Debug.output("CatName :" + this.catalog.getCatalogName());
            // continue;
            // }

            line = stripRedundant(line, this.catalog.getCatalogName());

            if (Debug.debugging("update")) {
                Debug.output("Data Line " + count + ":" + line);
            }

            // Read quake data
            try {
                QuakeAggregate qd = new QuakeAggregate();

                qd.setSource(NEIC_SOURCE_NAME);
                qd.setAgency(line.substring(25, 27));
                qd.setCatalogID(this.catalog.getCatalogID());
                qd.setCatalogName(this.catalog.getCatalogName());

                String d = line.substring(42, 45);
                if (empty(d)) {
                    qd.setDepth(0);
                } else {
                    qd.setDepth(Double.parseDouble(d));
                }

                qd.setLatitude(Double
                        .parseDouble(line.substring(27, 34).trim()));
                qd.setLongitude(Double.parseDouble(line.substring(34, 42)
                        .trim()));

                try {
                    time = getDateTime(line.substring(6, 25));
                } catch (UserException ex) {
                    Debug.error(ex.getMessage());
                    continue;
                }
                qd.setDateTime(time);
                qd.setFECode(Integer.parseInt(line.substring(87, 90).trim()));

                //
                // Read magnitude data
                //
                Collection mags = new ArrayList();

                boolean hasMs = false;

                loadMag(line.substring(54, 57), MB_MAGNITUDE, mags);
                hasMs = loadMag(line.substring(59, 62), MS_MAGNITUDE, mags);

                hasMs = loadMag(line.substring(65, 76), hasMs, mags);
                hasMs = loadMag(line.substring(76, 87), hasMs, mags);

                // One of the magnitude scales must be Ms
                // to allow insert in seismo-Surfer
                if (!hasMs) {
                    continue;
                }
                qd.setMagnitudes(mags);

                filtered.add(qd);
            } catch (NumberFormatException e) {
                Debug.error("One of the values is not in the expected format."
                        + e.getMessage());
                continue;
            }
        }
        data.clear();
    }

    protected boolean loadMag(String text, String type, Collection mags) {
        Assert.length(text, 3);

        boolean hasMs = false;

        MagData mag = new MagData();

        String m = text.substring(0, 3).trim();
        if (!empty(m)) {
            mag.setMagnitude(Double.parseDouble(m));
            mag.setMagnitudeType(type);
            mag.setMagnitudeAgency(NEIC_SOURCE_NAME);

            if (type.equalsIgnoreCase(MS_MAGNITUDE)) {
                hasMs = true;
            }
            mags.add(mag);
        }

        return hasMs;
    }

    protected boolean loadMag(String text, boolean hasMs, Collection mags) {
        Assert.length(text, 11);

        MagData mag = new MagData();

        String m = text.substring(0, 4).trim();
        String type = text.substring(4, 6).trim();
        if (!empty(m)) {
            if (!(type.equalsIgnoreCase(MS_MAGNITUDE) && hasMs)) {
                mag.setMagnitude(Double.parseDouble(m));
                mag.setMagnitudeType(type);
                mag.setMagnitudeAgency(text.substring(6, 11));

                if (type.equalsIgnoreCase(MS_MAGNITUDE)) {
                    hasMs = true;
                }
                mags.add(mag);
            }
        }

        return hasMs;
    }

    protected long getDateTime(String text) throws UserException {
        Assert.length(text, 19);

        String year = text.substring(0, 5);
        String month = text.substring(6, 8);
        String day = text.substring(8, 10);
        String hour = text.substring(10, 12);
        String min = text.substring(12, 14);
        String sec = text.substring(14);

        // year
        if (empty(year)) {
            throw new UserException("Date cannot be parsed: No year.");
        }

        if (year.startsWith("-")) {
            int index = year.indexOf("-");
            year = "-" + year.substring(index + 1).trim();
        }

        month = empty(month, " 1");
        day = empty(day, " 1");
        hour = empty(hour, " 0");
        min = empty(min, " 0");

        // second
        if (empty(sec)) {
            sec = " 0";
        } else {
            try {
                int second = Math.round(Float.parseFloat(sec));
                if (second == 60) {
                    second = 59;
                }
                sec = String.valueOf(second);
            } catch (NumberFormatException ex) {
                sec = " 0";
            }
        }
        try {
            return TimeUtil.toDate(year + month + day + hour + min + sec);
        } catch (ParseException e) {
            throw new UserException("Date cannot be parsed:" + e.getMessage());
        }
    }

}